﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DotNetCommon.Extensions;
using System.Data.Common;
using System.Diagnostics;

namespace DBUtil
{
    /// <summary>
    /// 通用数据库访问对象
    /// </summary>
    public abstract partial class DBAccess
    {
        #region 执行sql语句 ExecuteSql...
        public virtual async Task<int> ExecuteSqlAsync(string sql, CancellationToken cancellationToken = default)
            => await ExecuteSqlAsync(sql, null, null, [], cancellationToken);

        public virtual async Task<int> ExecuteSqlAsync(string sql, IDictionary<string, object> dic, CancellationToken cancellationToken = default)
            => await ExecuteSqlAsync(sql, null, null, dic?.Keys.Select(key => CreatePara(key, dic[key])).ToArray(), cancellationToken);

        public virtual async Task<int> ExecuteSqlAsync(string sql, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
            => await ExecuteSqlAsync(sql, null, null, parameters, cancellationToken);

        public virtual async Task<int> ExecuteSqlAsync(string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            Stopwatch st = null;
            Exception ex = null;
            if (Setting.HasMonitor) { st = new Stopwatch(); st.Start(); }
            try
            {
                return await RunInCommandAsync(async cmd => await cmd.ExecuteNonQueryAsync(cancellationToken), sql, commandType, timeoutSecond, parameters);
            }
            catch (Exception e)
            {
                if (Setting.HasMonitor) ex = e;
                throw;
            }
            finally
            {
                if (Setting.HasMonitor)
                {
                    if (st.IsRunning) st.Stop();
                    await Setting.MonitorAction?.Invoke(new MonitorArgument
                    {
                        Sql = sql,
                        Exception = ex,
                        TimeSpan = TimeSpan.FromMilliseconds(st.ElapsedMilliseconds)
                    });
                }
            }
        }
        #endregion

        #region 查询语句 Select...

        #region SelectScalarAsync
        public async virtual Task<T> SelectScalarAsync<T>(string sql, CancellationToken cancellationToken = default)
            => await SelectScalarAsync<T>(sql, null, null, null, cancellationToken);

        public async virtual Task<T> SelectScalarAsync<T>(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectScalarAsync<T>(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<T> SelectScalarAsync<T>(string sql, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
            => await SelectScalarAsync<T>(sql, null, null, parameters, cancellationToken);

        public async virtual Task<T> SelectScalarAsync<T>(string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            Stopwatch st = null;
            Exception ex = null;
            if (Setting.HasMonitor) { st = new Stopwatch(); st.Start(); }
            try
            {
                return await RunInCommandAsync(async cmd =>
                {
                    var res = await cmd.ExecuteScalarAsync(cancellationToken);
                    return res.To<T>();
                }, sql, commandType, timeoutSecond, parameters);
            }
            catch (Exception e)
            {
                if (Setting.HasMonitor) ex = e;
                throw;
            }
            finally
            {
                if (Setting.HasMonitor)
                {
                    if (st.IsRunning) st.Stop();
                    await Setting.MonitorAction?.Invoke(new MonitorArgument
                    {
                        Sql = sql,
                        Exception = ex,
                        TimeSpan = TimeSpan.FromMilliseconds(st.ElapsedMilliseconds)
                    });
                }
            }
        }
        #endregion

        #region SelectDataSetAsync
        public virtual async Task<DataSet> SelectDataSetAsync(string sql, CancellationToken cancellationToken = default)
            => await SelectDataSetAsync(sql, null, null, null, cancellationToken);

        public virtual async Task<DataSet> SelectDataSetAsync(string sql, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
            => await SelectDataSetAsync(sql, null, null, parameters, cancellationToken);

        public virtual async Task<DataSet> SelectDataSetAsync(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDataSetAsync(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public virtual async Task<DataSet> SelectDataSetAsync(string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            //这里不用再使用 RunInCommand 包裹, 也不用再检测耗时, 因为 SelectDataReaderAsync 里面已经做了
            return await SelectDataReaderAsync(async reader =>
            {
                DataSet set = new();
                do
                {
                    var dt = new DataTable();
                    var count = reader.RawReader.FieldCount;
                    for (int i = 0; i < count; i++)
                    {
                        dt.Columns.Add(new DataColumn(reader.RawReader.GetName(i), reader.RawReader.GetFieldType(i)));
                    }
                    while (await reader.RawReader.ReadAsync(cancellationToken))
                    {
                        var arr = new object[count];
                        reader.RawReader.GetValues(arr);
                        dt.Rows.Add(arr);
                    }
                    set.Tables.Add(dt);
                } while (await reader.RawReader.NextResultAsync(cancellationToken));
                return set;
            }, sql, commandType, timeoutSecond, parameters, cancellationToken);
        }
        #endregion

        #region SelectDataTableAsync
        public virtual async Task<DataTable> SelectDataTableAsync(string sql, CancellationToken cancellationToken = default)
            => await SelectDataTableAsync(sql, null, null, null, cancellationToken);

        public virtual async Task<DataTable> SelectDataTableAsync(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDataTableAsync(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public virtual async Task<DataTable> SelectDataTableAsync(string sql, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
            => await SelectDataTableAsync(sql, null, null, parameters, cancellationToken);

        public virtual async Task<DataTable> SelectDataTableAsync(string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            //这里不用再使用 RunInCommand 包裹, 也不用再检测耗时, 因为 SelectDataReaderAsync 里面已经做了
            return await SelectDataReaderAsync(async reader =>
             {
                 var dt = new DataTable();
                 var count = reader.RawReader.FieldCount;
                 for (int i = 0; i < count; i++)
                 {
                     dt.Columns.Add(new DataColumn(reader.RawReader.GetName(i), reader.RawReader.GetFieldType(i)));
                 }
                 while (await reader.RawReader.ReadAsync(cancellationToken))
                 {
                     var arr = new object[count];
                     reader.RawReader.GetValues(arr);
                     dt.Rows.Add(arr);
                 }
                 return dt;
             }, sql, commandType, timeoutSecond, parameters, cancellationToken);
        }
        #endregion

        #region SelectDataReaderAsync

        #region SelectDataReaderAsync Action
        public async virtual Task SelectDataReaderAsync(Func<DBUtilDataReader, Task> func, string sql, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, sql, null, null, null, cancellationToken);

        public async virtual Task SelectDataReaderAsync(Func<DBUtilDataReader, Task> func, string sql, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, sql, null, null, parameters, cancellationToken);

        public async virtual Task SelectDataReaderAsync(Func<DBUtilDataReader, Task> func, string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task SelectDataReaderAsync(Func<DBUtilDataReader, Task> func, string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            if (func == null) throw new Exception("执行的逻辑不能为空!");
            Stopwatch st = null;
            Exception ex = null;
            if (Setting.HasMonitor) { st = new Stopwatch(); st.Start(); }
            try
            {
                await RunInCommandAsync(async cmd =>
                {
                    var reader = await cmd.ExecuteReaderAsync(cancellationToken);
                    try
                    {
                        await func(new DBUtilDataReader { RawReader = reader, db = this });
                    }
                    finally
                    {
                        if (!reader.IsClosed)
                        {
                            try { await reader.CloseAsync(); }
                            catch (Exception ex) { logger.LogError(ex, $"释放 DbDataReader 时报错:{ex.Message}"); };
                        }
                    }
                }, sql, commandType, timeoutSecond, parameters);
            }
            catch (Exception e)
            {
                if (Setting.HasMonitor) ex = e;
                throw;
            }
            finally
            {
                if (Setting.HasMonitor)
                {
                    if (st.IsRunning) st.Stop();
                    await Setting.MonitorAction?.Invoke(new MonitorArgument
                    {
                        Sql = sql,
                        Exception = ex,
                        TimeSpan = TimeSpan.FromMilliseconds(st.ElapsedMilliseconds)
                    });
                }
            }
        }
        #endregion

        #region SelectDataReaderAsync Func
        public async virtual Task<T> SelectDataReaderAsync<T>(Func<DBUtilDataReader, Task<T>> func, string sql, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, sql, null, null, null, cancellationToken);

        public async virtual Task<T> SelectDataReaderAsync<T>(Func<DBUtilDataReader, Task<T>> func, string sql, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, sql, null, null, parameters, cancellationToken);

        public async virtual Task<T> SelectDataReaderAsync<T>(Func<DBUtilDataReader, Task<T>> func, string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<T> SelectDataReaderAsync<T>(Func<DBUtilDataReader, Task<T>> func, string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            return (T)await SelectDataReaderAsync(typeof(T), async (reader) => await func(reader), sql, commandType, timeoutSecond, parameters, cancellationToken);
        }

        public async virtual Task<object> SelectDataReaderAsync(Type type, Func<DBUtilDataReader, Task<object>> func, string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            if (func == null) throw new Exception("执行的逻辑不能为空!");
            Stopwatch st = null;
            Exception ex = null;
            if (Setting.HasMonitor) { st = new Stopwatch(); st.Start(); }
            try
            {
                return await RunInCommandAsync(async cmd =>
                {
                    var reader = await cmd.ExecuteReaderAsync(cancellationToken);
                    try
                    {
                        object result = type.GetDefault();
                        if (func != null) result = await func(new DBUtilDataReader { RawReader = reader, db = this });
                        return result;
                    }
                    finally
                    {
                        if (!reader.IsClosed)
                        {
                            try { await reader.CloseAsync(); }
                            catch (Exception ex) { logger.LogError(ex, $"释放 DbDataReader 时报错:{ex.Message}"); };
                        }
                    }
                }, sql, commandType, timeoutSecond, parameters);
            }
            catch (Exception e)
            {
                if (Setting.HasMonitor) ex = e;
                throw;
            }
            finally
            {
                if (Setting.HasMonitor)
                {
                    if (st.IsRunning) st.Stop();
                    await Setting.MonitorAction?.Invoke(new MonitorArgument
                    {
                        Exception = ex,
                        Sql = sql,
                        TimeSpan = TimeSpan.FromMilliseconds(st.ElapsedMilliseconds)
                    });
                }
            }
        }
        #endregion

        #endregion

        #region SelectModelAsync

        #region SelectModelAsync
        public async virtual Task<T> SelectModelAsync<T>(string sql, CancellationToken cancellationToken = default)
            => await SelectModelAsync<T>(sql, null, null, null, cancellationToken);

        public async virtual Task<T> SelectModelAsync<T>(string sql, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
            => await SelectModelAsync<T>(sql, null, null, parameters, cancellationToken);

        public async virtual Task<T> SelectModelAsync<T>(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectModelAsync<T>(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<T> SelectModelAsync<T>(string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync(async reader => await reader.ReadOneAsync<T>(), sql, commandType, timeoutSecond, parameters, cancellationToken);
        }
        public async virtual Task<object> SelectModelAsync(Type type, string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync(type, async reader => await reader.ReadOneAsync(type), sql, commandType, timeoutSecond, parameters, cancellationToken);
        }
        #endregion

        #region SelectModelListAsync
        public async virtual Task<List<T>> SelectModelListAsync<T>(string sql, CancellationToken cancellationToken = default)
            => await SelectModelListAsync<T>(sql, null, null, null, cancellationToken);

        public async virtual Task<List<T>> SelectModelListAsync<T>(string sql, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
            => await SelectModelListAsync<T>(sql, null, null, parameters, cancellationToken);

        public async virtual Task<List<T>> SelectModelListAsync<T>(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectModelListAsync<T>(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<List<T>> SelectModelListAsync<T>(string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync(async reader => await reader.ReadListAsync<T>(), sql, commandType, timeoutSecond, parameters, cancellationToken);
        }
        #endregion

        #endregion

        #region SelectDictionaryAsync

        #region SelectDictionaryAsync
        public async virtual Task<Dictionary<string, object>> SelectDictionaryAsync(string sql, CancellationToken cancellationToken = default)
            => await SelectDictionaryAsync(sql, null, null, null, cancellationToken);

        public async virtual Task<Dictionary<string, object>> SelectDictionaryAsync(string sql, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
            => await SelectDictionaryAsync(sql, null, null, parameters, cancellationToken);

        public async virtual Task<Dictionary<string, object>> SelectDictionaryAsync(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDictionaryAsync(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<Dictionary<string, object>> SelectDictionaryAsync(string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync(async reader =>
            {
                Dictionary<string, object> dic = null;
                var count = reader.RawReader.FieldCount;
                if (await reader.RawReader.ReadAsync(cancellationToken))
                {
                    dic = [];
                    for (int i = 0; i < count; i++)
                    {
                        dic[reader.RawReader.GetName(i)] = reader.RawReader.GetValue(i);
                    }
                }
                return dic;
            }, sql, commandType, timeoutSecond, parameters, cancellationToken);
        }
        #endregion

        #region SelectDictionaryListAsync
        public async virtual Task<List<Dictionary<string, object>>> SelectDictionaryListAsync(string sql, CancellationToken cancellationToken = default)
            => await SelectDictionaryListAsync(sql, null, null, null, cancellationToken);

        public async virtual Task<List<Dictionary<string, object>>> SelectDictionaryListAsync(string sql, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
            => await SelectDictionaryListAsync(sql, null, null, parameters, cancellationToken);

        public async virtual Task<List<Dictionary<string, object>>> SelectDictionaryListAsync(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDictionaryListAsync(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<List<Dictionary<string, object>>> SelectDictionaryListAsync(string sql, CommandType? commandType, int? timeoutSecond, IEnumerable<DbParameter> parameters, CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync(async reader =>
            {
                var count = reader.RawReader.FieldCount;
                var names = new string[count];
                for (int i = 0; i < count; i++)
                {
                    names[i] = reader.RawReader.GetName(i);
                }
                var list = new List<Dictionary<string, object>>();
                while (await reader.RawReader.ReadAsync(cancellationToken))
                {
                    var dic = new Dictionary<string, object>();
                    list.Add(dic);
                    for (int i = 0; i < count; i++)
                    {
                        dic[names[i]] = reader.RawReader.GetValue(i);
                    }
                }
                return list;
            }, sql, commandType, timeoutSecond, parameters, cancellationToken);
        }
        #endregion

        #endregion

        #region SelectMultipleAsync
        /// <summary>
        /// 批量查询(返回多个结果集)
        /// </summary>
        public virtual async Task<(T, T2)> SelectMultipleAsync<T, T2>(string sql
            , Func<DBUtilDataReader, Task<T>> func
            , Func<DBUtilDataReader, Task<T2>> func2
            , int? timeoutSecond = null
            , CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync<(T, T2)>(async (reader) =>
            {
                var t1 = await func(reader);
                await reader.RawReader.NextResultAsync();
                var t2 = await func2(reader);
                return (t1, t2);
            }, sql, commandType: null, timeoutSecond: timeoutSecond, parameters: null, cancellationToken: cancellationToken);
        }
        /// <summary>
        /// 批量查询(返回多个结果集)
        /// </summary>
        public virtual async Task<(T, T2, T3)> SelectMultipleAsync<T, T2, T3>(string sql
            , Func<DBUtilDataReader, Task<T>> func
            , Func<DBUtilDataReader, Task<T2>> func2
            , Func<DBUtilDataReader, Task<T3>> func3
            , int? timeoutSecond = null
            , CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync<(T, T2, T3)>(async (reader) =>
            {
                var t1 = await func(reader);
                await reader.RawReader.NextResultAsync();
                var t2 = await func2(reader);
                await reader.RawReader.NextResultAsync();
                var t3 = await func3(reader);
                return (t1, t2, t3);
            }, sql, commandType: null, timeoutSecond: timeoutSecond, parameters: null, cancellationToken: cancellationToken);
        }
        /// <summary>
        /// 批量查询(返回多个结果集)
        /// </summary>
        public virtual async Task<(T, T2, T3, T4)> SelectMultipleAsync<T, T2, T3, T4>(string sql
            , Func<DBUtilDataReader, Task<T>> func
            , Func<DBUtilDataReader, Task<T2>> func2
            , Func<DBUtilDataReader, Task<T3>> func3
            , Func<DBUtilDataReader, Task<T4>> func4
            , int? timeoutSecond = null
            , CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync<(T, T2, T3, T4)>(async (reader) =>
            {
                var t1 = await func(reader);
                await reader.RawReader.NextResultAsync();
                var t2 = await func2(reader);
                await reader.RawReader.NextResultAsync();
                var t3 = await func3(reader);
                await reader.RawReader.NextResultAsync();
                var t4 = await func4(reader);
                return (t1, t2, t3, t4);
            }, sql, commandType: null, timeoutSecond: timeoutSecond, parameters: null, cancellationToken: cancellationToken);
        }
        /// <summary>
        /// 批量查询(返回多个结果集)
        /// </summary>
        public virtual async Task<(T, T2, T3, T4, T5)> SelectMultipleAsync<T, T2, T3, T4, T5>(string sql
            , Func<DBUtilDataReader, Task<T>> func
            , Func<DBUtilDataReader, Task<T2>> func2
            , Func<DBUtilDataReader, Task<T3>> func3
            , Func<DBUtilDataReader, Task<T4>> func4
            , Func<DBUtilDataReader, Task<T5>> func5
            , int? timeoutSecond = null
            , CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync<(T, T2, T3, T4, T5)>(async (reader) =>
            {
                var t1 = await func(reader);
                await reader.RawReader.NextResultAsync();
                var t2 = await func2(reader);
                await reader.RawReader.NextResultAsync();
                var t3 = await func3(reader);
                await reader.RawReader.NextResultAsync();
                var t4 = await func4(reader);
                await reader.RawReader.NextResultAsync();
                var t5 = await func5(reader);
                return (t1, t2, t3, t4, t5);
            }, sql, commandType: null, timeoutSecond: timeoutSecond, parameters: null, cancellationToken: cancellationToken);
        }
        /// <summary>
        /// 批量查询(返回多个结果集)
        /// </summary>
        public virtual async Task<(T, T2, T3, T4, T5, T6)> SelectMultipleAsync<T, T2, T3, T4, T5, T6>(string sql
            , Func<DBUtilDataReader, Task<T>> func
            , Func<DBUtilDataReader, Task<T2>> func2
            , Func<DBUtilDataReader, Task<T3>> func3
            , Func<DBUtilDataReader, Task<T4>> func4
            , Func<DBUtilDataReader, Task<T5>> func5
            , Func<DBUtilDataReader, Task<T6>> func6
            , int? timeoutSecond = null
            , CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync<(T, T2, T3, T4, T5, T6)>(async (reader) =>
            {
                var t1 = await func(reader);
                await reader.RawReader.NextResultAsync();
                var t2 = await func2(reader);
                await reader.RawReader.NextResultAsync();
                var t3 = await func3(reader);
                await reader.RawReader.NextResultAsync();
                var t4 = await func4(reader);
                await reader.RawReader.NextResultAsync();
                var t5 = await func5(reader);
                await reader.RawReader.NextResultAsync();
                var t6 = await func6(reader);
                return (t1, t2, t3, t4, t5, t6);
            }, sql, commandType: null, timeoutSecond: timeoutSecond, parameters: null, cancellationToken: cancellationToken);
        }
        /// <summary>
        /// 批量查询(返回多个结果集)
        /// </summary>
        public virtual async Task<(T, T2, T3, T4, T5, T6, T7)> SelectMultipleAsync<T, T2, T3, T4, T5, T6, T7>(string sql
            , Func<DBUtilDataReader, Task<T>> func
            , Func<DBUtilDataReader, Task<T2>> func2
            , Func<DBUtilDataReader, Task<T3>> func3
            , Func<DBUtilDataReader, Task<T4>> func4
            , Func<DBUtilDataReader, Task<T5>> func5
            , Func<DBUtilDataReader, Task<T6>> func6
            , Func<DBUtilDataReader, Task<T7>> func7
            , int? timeoutSecond = null
            , CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync<(T, T2, T3, T4, T5, T6, T7)>(async (reader) =>
            {
                var t1 = await func(reader);
                await reader.RawReader.NextResultAsync();
                var t2 = await func2(reader);
                await reader.RawReader.NextResultAsync();
                var t3 = await func3(reader);
                await reader.RawReader.NextResultAsync();
                var t4 = await func4(reader);
                await reader.RawReader.NextResultAsync();
                var t5 = await func5(reader);
                await reader.RawReader.NextResultAsync();
                var t6 = await func6(reader);
                await reader.RawReader.NextResultAsync();
                var t7 = await func7(reader);
                return (t1, t2, t3, t4, t5, t6, t7);
            }, sql, commandType: null, timeoutSecond: timeoutSecond, parameters: null, cancellationToken: cancellationToken);
        }
        /// <summary>
        /// 批量查询(返回多个结果集)
        /// </summary>
        public virtual async Task<(T, T2, T3, T4, T5, T6, T7, T8)> SelectMultipleAsync<T, T2, T3, T4, T5, T6, T7, T8>(string sql
            , Func<DBUtilDataReader, Task<T>> func
            , Func<DBUtilDataReader, Task<T2>> func2
            , Func<DBUtilDataReader, Task<T3>> func3
            , Func<DBUtilDataReader, Task<T4>> func4
            , Func<DBUtilDataReader, Task<T5>> func5
            , Func<DBUtilDataReader, Task<T6>> func6
            , Func<DBUtilDataReader, Task<T7>> func7
            , Func<DBUtilDataReader, Task<T8>> func8
            , int? timeoutSecond = null
            , CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync<(T, T2, T3, T4, T5, T6, T7, T8)>(async (reader) =>
            {
                var t1 = await func(reader);
                await reader.RawReader.NextResultAsync();
                var t2 = await func2(reader);
                await reader.RawReader.NextResultAsync();
                var t3 = await func3(reader);
                await reader.RawReader.NextResultAsync();
                var t4 = await func4(reader);
                await reader.RawReader.NextResultAsync();
                var t5 = await func5(reader);
                await reader.RawReader.NextResultAsync();
                var t6 = await func6(reader);
                await reader.RawReader.NextResultAsync();
                var t7 = await func7(reader);
                await reader.RawReader.NextResultAsync();
                var t8 = await func8(reader);
                return (t1, t2, t3, t4, t5, t6, t7, t8);
            }, sql, commandType: null, timeoutSecond: timeoutSecond, parameters: null, cancellationToken: cancellationToken);
        }
        /// <summary>
        /// 批量查询(返回多个结果集)
        /// </summary>
        public virtual async Task<(T, T2, T3, T4, T5, T6, T7, T8, T9)> SelectMultipleAsync<T, T2, T3, T4, T5, T6, T7, T8, T9>(string sql
            , Func<DBUtilDataReader, Task<T>> func
            , Func<DBUtilDataReader, Task<T2>> func2
            , Func<DBUtilDataReader, Task<T3>> func3
            , Func<DBUtilDataReader, Task<T4>> func4
            , Func<DBUtilDataReader, Task<T5>> func5
            , Func<DBUtilDataReader, Task<T6>> func6
            , Func<DBUtilDataReader, Task<T7>> func7
            , Func<DBUtilDataReader, Task<T8>> func8
            , Func<DBUtilDataReader, Task<T9>> func9
            , int? timeoutSecond = null
            , CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync<(T, T2, T3, T4, T5, T6, T7, T8, T9)>(async (reader) =>
            {
                var t1 = await func(reader);
                await reader.RawReader.NextResultAsync();
                var t2 = await func2(reader);
                await reader.RawReader.NextResultAsync();
                var t3 = await func3(reader);
                await reader.RawReader.NextResultAsync();
                var t4 = await func4(reader);
                await reader.RawReader.NextResultAsync();
                var t5 = await func5(reader);
                await reader.RawReader.NextResultAsync();
                var t6 = await func6(reader);
                await reader.RawReader.NextResultAsync();
                var t7 = await func7(reader);
                await reader.RawReader.NextResultAsync();
                var t8 = await func8(reader);
                await reader.RawReader.NextResultAsync();
                var t9 = await func9(reader);
                return (t1, t2, t3, t4, t5, t6, t7, t8, t9);
            }, sql, commandType: null, timeoutSecond: timeoutSecond, parameters: null, cancellationToken: cancellationToken);
        }
        /// <summary>
        /// 批量查询(返回多个结果集)
        /// </summary>
        public virtual async Task<(T, T2, T3, T4, T5, T6, T7, T8, T9, T10)> SelectMultipleAsync<T, T2, T3, T4, T5, T6, T7, T8, T9, T10>(string sql
            , Func<DBUtilDataReader, Task<T>> func
            , Func<DBUtilDataReader, Task<T2>> func2
            , Func<DBUtilDataReader, Task<T3>> func3
            , Func<DBUtilDataReader, Task<T4>> func4
            , Func<DBUtilDataReader, Task<T5>> func5
            , Func<DBUtilDataReader, Task<T6>> func6
            , Func<DBUtilDataReader, Task<T7>> func7
            , Func<DBUtilDataReader, Task<T8>> func8
            , Func<DBUtilDataReader, Task<T9>> func9
            , Func<DBUtilDataReader, Task<T10>> func10
            , int? timeoutSecond = null
            , CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync<(T, T2, T3, T4, T5, T6, T7, T8, T9, T10)>(async (reader) =>
            {
                var t1 = await func(reader);
                await reader.RawReader.NextResultAsync();
                var t2 = await func2(reader);
                await reader.RawReader.NextResultAsync();
                var t3 = await func3(reader);
                await reader.RawReader.NextResultAsync();
                var t4 = await func4(reader);
                await reader.RawReader.NextResultAsync();
                var t5 = await func5(reader);
                await reader.RawReader.NextResultAsync();
                var t6 = await func6(reader);
                await reader.RawReader.NextResultAsync();
                var t7 = await func7(reader);
                await reader.RawReader.NextResultAsync();
                var t8 = await func8(reader);
                await reader.RawReader.NextResultAsync();
                var t9 = await func9(reader);
                await reader.RawReader.NextResultAsync();
                var t10 = await func10(reader);
                return (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
            }, sql, commandType: null, timeoutSecond: timeoutSecond, parameters: null, cancellationToken: cancellationToken);
        }
        #endregion

        #endregion
    }
}
